{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Auto Generated Agent Chat: Collaborative Task Solving with Multiple Agents and Human Users\n",
    "\n",
    "AG2 offers conversable agents powered by LLM, tool, or human, which can be used to perform tasks collectively via automated chat. This framework allows tool use and human participation through multi-agent conversation. Please find documentation about this feature [here](https://docs.ag2.ai/latest/docs/user-guide/basic-concepts/conversable-agent/).\n",
    "\n",
    "In this notebook, we demonstrate an application involving multiple agents and human users to work together and accomplish a task. `AssistantAgent` is an LLM-based agent that can write Python code (in a Python coding block) for a user to execute for a given task. `UserProxyAgent` is an agent which serves as a proxy for a user to execute the code written by `AssistantAgent`. We create multiple `UserProxyAgent` instances that can represent different human users.\n",
    "\n",
    "## Requirements\n",
    "\n",
    "AG2 requires `Python>=3.9`. To run this notebook example, please install:\n",
    "```bash\n",
    "pip install autogen[openai]\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %pip install \"autogen\""
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Set your API Endpoint\n",
    "\n",
    "The [`config_list_from_json`](https://docs.ag2.ai/latest/docs/api-reference/autogen/config_list_from_json/#autogen.config_list_from_json) function loads a list of configurations from an environment variable or a json file.\n",
    "\n",
    "It first looks for an environment variable of a specified name (\"OAI_CONFIG_LIST\" in this example), which needs to be a valid json string. If that variable is not found, it looks for a json file with the same name. It filters the configs by models (you can filter by other keys as well).\n",
    "\n",
    "The json looks like the following:\n",
    "```json\n",
    "[\n",
    "    {\n",
    "        \"model\": \"gpt-4\",\n",
    "        \"api_key\": \"<your OpenAI API key here>\"\n",
    "    },\n",
    "    {\n",
    "        \"model\": \"gpt-4\",\n",
    "        \"api_key\": \"<your Azure OpenAI API key here>\",\n",
    "        \"base_url\": \"<your Azure OpenAI API base here>\",\n",
    "        \"api_type\": \"azure\",\n",
    "        \"api_version\": \"2024-02-01\"\n",
    "    },\n",
    "    {\n",
    "        \"model\": \"gpt-4-32k\",\n",
    "        \"api_key\": \"<your Azure OpenAI API key here>\",\n",
    "        \"base_url\": \"<your Azure OpenAI API base here>\",\n",
    "        \"api_type\": \"azure\",\n",
    "        \"api_version\": \"2024-02-01\"\n",
    "    }\n",
    "]\n",
    "```\n",
    "\n",
    "You can set the value of config_list in any way you prefer. Please refer to this [User Guide](https://docs.ag2.ai/latest/docs/user-guide/advanced-concepts/llm-configuration-deep-dive) for full code examples of the different methods."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import autogen\n",
    "\n",
    "config_list = autogen.config_list_from_json(\n",
    "    \"OAI_CONFIG_LIST\",\n",
    "    filter_dict={\n",
    "        \"model\": [\"gpt-4\", \"gpt4\", \"gpt-4-32k\", \"gpt-4-32k-0314\", \"gpt-4-32k-v0314\"],\n",
    "    },\n",
    ")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Construct Agents\n",
    "\n",
    "We define `ask_expert` function to start a conversation between two agents and return a summary of the result. We construct an assistant agent named \"assistant_for_expert\" and a user proxy agent named \"expert\". We specify `human_input_mode` as \"ALWAYS\" in the user proxy agent, which will always ask for feedback from the expert user."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def ask_expert(message):\n",
    "    assistant_for_expert = autogen.AssistantAgent(\n",
    "        name=\"assistant_for_expert\",\n",
    "        llm_config={\n",
    "            \"temperature\": 0,\n",
    "            \"config_list\": config_list,\n",
    "        },\n",
    "    )\n",
    "    expert = autogen.UserProxyAgent(\n",
    "        name=\"expert\",\n",
    "        human_input_mode=\"ALWAYS\",\n",
    "        code_execution_config={\n",
    "            \"work_dir\": \"expert\",\n",
    "            \"use_docker\": False,\n",
    "        },  # Please set use_docker=True if docker is available to run the generated code. Using docker is safer than running the generated code directly.\n",
    "    )\n",
    "\n",
    "    expert.initiate_chat(assistant_for_expert, message=message)\n",
    "    expert.stop_reply_at_receive(assistant_for_expert)\n",
    "    # expert.human_input_mode, expert.max_consecutive_auto_reply = \"NEVER\", 0\n",
    "    # final message sent from the expert\n",
    "    expert.send(\"summarize the solution and explain the answer in an easy-to-understand way\", assistant_for_expert)\n",
    "    # return the last message the expert received\n",
    "    return expert.last_message()[\"content\"]"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We construct another assistant agent named \"assistant_for_student\" and a user proxy agent named \"student\". We specify `human_input_mode` as \"TERMINATE\" in the user proxy agent, which will ask for feedback when it receives a \"TERMINATE\" signal from the assistant agent. We set the `functions` in `AssistantAgent` and `function_map` in `UserProxyAgent` to use the created `ask_expert` function.\n",
    "\n",
    "For simplicity, the `ask_expert` function is defined to run locally. For real applications, the function should run remotely to interact with an expert user."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "assistant_for_student = autogen.AssistantAgent(\n",
    "    name=\"assistant_for_student\",\n",
    "    system_message=\"You are a helpful assistant. Reply TERMINATE when the task is done.\",\n",
    "    llm_config={\n",
    "        \"timeout\": 600,\n",
    "        \"cache_seed\": 42,\n",
    "        \"config_list\": config_list,\n",
    "        \"temperature\": 0,\n",
    "        \"functions\": [\n",
    "            {\n",
    "                \"name\": \"ask_expert\",\n",
    "                \"description\": \"ask expert when you can't solve the problem satisfactorily.\",\n",
    "                \"parameters\": {\n",
    "                    \"type\": \"object\",\n",
    "                    \"properties\": {\n",
    "                        \"message\": {\n",
    "                            \"type\": \"string\",\n",
    "                            \"description\": \"question to ask expert. Ensure the question includes enough context, such as the code and the execution result. The expert does not know the conversation between you and the user unless you share the conversation with the expert.\",\n",
    "                        },\n",
    "                    },\n",
    "                    \"required\": [\"message\"],\n",
    "                },\n",
    "            }\n",
    "        ],\n",
    "    },\n",
    ")\n",
    "\n",
    "student = autogen.UserProxyAgent(\n",
    "    name=\"student\",\n",
    "    human_input_mode=\"TERMINATE\",\n",
    "    max_consecutive_auto_reply=10,\n",
    "    code_execution_config={\n",
    "        \"work_dir\": \"student\",\n",
    "        \"use_docker\": False,\n",
    "    },  # Please set use_docker=True if docker is available to run the generated code. Using docker is safer than running the generated code directly.\n",
    "    function_map={\"ask_expert\": ask_expert},\n",
    ")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Perform a task\n",
    "\n",
    "We invoke the `initiate_chat()` method of the student proxy agent to start the conversation. When you run the cell below, you will be prompted to provide feedback after the assistant agent sends a \"TERMINATE\" signal at the end of the message. The conversation will finish if you don't provide any feedback (by pressing Enter directly). Before the \"TERMINATE\" signal, the student proxy agent will try to execute the code suggested by the assistant agent on behalf of the user."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# the assistant receives a message from the student, which contains the task description\n",
    "student.initiate_chat(\n",
    "    assistant_for_student,\n",
    "    message=\"\"\"Find $a + b + c$, given that $x+y \\\\neq -1$ and\n",
    "\\\\begin{align}\n",
    "\tax + by + c & = x + 7,\\\\\n",
    "\ta + bx + cy & = 2x + 6y,\\\\\n",
    "\tay + b + cx & = 4x + y.\n",
    "\\\\end{align}.\n",
    "\"\"\",\n",
    ")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When the assistant needs to consult the expert, it suggests a function call to `ask_expert`. When this happens, a line like the following will be displayed:\n",
    "\n",
    "***** Suggested function Call: ask_expert *****\n"
   ]
  }
 ],
 "metadata": {
  "front_matter": {
   "description": "Involve multiple human users via function calls and nested chat.",
   "tags": [
    "human",
    "tool/function"
   ]
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.17"
  },
  "vscode": {
   "interpreter": {
    "hash": "949777d72b0d2535278d3dc13498b2535136f6dfe0678499012e853ee9abcab1"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
